// Fill out your copyright notice in the Description page of Project Settings.


#include "NetworkGameInstance.h"
#include "NetworkController.h"
#include "OnlineSubsystemUtils.h"
#include "GameFramework/GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "Subsystem/GameVersionSubsystem.h"

void UNetworkGameInstance::Init()
{
	Super::Init();
	MapPath = FString("/Game/ThirdPerson/ThirdPersonCPP/Maps/ThirdPersonExampleMap?listen");
	MapLeftPath = FString("/Game/ThirdPerson/ThirdPersonCPP/Maps/");
	GameVersionSubsystem = GetSubsystem<UGameVersionSubsystem>();
}

void UNetworkGameInstance::MountedAllPaks(TEnumAsByte<DownloadResult> Result)
{
	if (Result == DownloadResult::SuccessDownloading && GameVersionSubsystem)
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));
		GameVersionSubsystem->OnAllPakDownloadComplete().RemoveAll(this);
		GameVersionSubsystem->MountPak();
		UGameplayStatics::OpenLevel(GetWorld(), TEXT("ThirdPersonExampleMap"));
	}
}

ANetworkGameSession* UNetworkGameInstance::GetGameSession()
{
	UWorld* const World = GetWorld();
	if (World)
	{
		AGameModeBase* const Game = World->GetAuthGameMode();
		if (Game)
		{
			return Cast<ANetworkGameSession>(Game->GameSession);
		}
	}

	return nullptr;
}

void UNetworkGameInstance::FinishSessionCreation(EOnJoinSessionCompleteResult::Type Result)
{
	if (Result == EOnJoinSessionCompleteResult::Success)
	{
		GetWorld()->ServerTravel(TravelURL);
	} else { }
}

void UNetworkGameInstance::FinishJoinSession(EOnJoinSessionCompleteResult::Type Result)
{
	InternalTravelToSession(NAME_GameSession);
}

void UNetworkGameInstance::InternalTravelToSession(const FName& SessionName)
{
	APlayerController* PC = GetFirstLocalPlayerController();
	IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
	if (PC && Subsystem)
	{
		IOnlineSessionPtr SessionPtr = Subsystem->GetSessionInterface();
		FString ConnectInfo;
		if (SessionPtr.IsValid() && SessionPtr->GetResolvedConnectString(SessionName, ConnectInfo))
		{
			PC->ClientTravel(ConnectInfo, ETravelType::TRAVEL_Absolute);
		}
	}
}

void UNetworkGameInstance::OnJoinSessionComplete(EOnJoinSessionCompleteResult::Type Result)
{
	ANetworkGameSession* const GameSession = GetGameSession();
	if (GameSession)
	{
		GameSession->OnJoinSessionComplete().Remove(OnJoinSessionCompleteDelegateHandle);
	}
	FinishJoinSession(Result);
}

bool UNetworkGameInstance::FindSessions(ULocalPlayer* PlayerOwner, bool bIsDedicatedServer, bool bFindLAN)
{
	if (PlayerOwner)
	{
		ANetworkGameSession* const GameSession = GetGameSession();
		if (GameSession)
		{
			GameSession->OnFindSessionsComplete().RemoveAll(this);
			OnSearchSessionsCompleteDelegateHandle = GameSession->OnFindSessionsComplete().AddUObject(this, &UNetworkGameInstance::OnSearchSessionsComplete);
			GameSession->FindSession(PlayerOwner->GetPreferredUniqueNetId().GetUniqueNetId(), NAME_GameSession, bFindLAN, !bIsDedicatedServer);
		}
	}
	return false;
}

void UNetworkGameInstance::OnSearchSessionsComplete(bool bWasSuccessful)
{
	ANetworkGameSession* const Session = GetGameSession();
	if (Session)
	{
		Session->OnFindSessionsComplete().Remove(OnSearchSessionsCompleteDelegateHandle);
	}
}

void UNetworkGameInstance::DebugMessage(FString Message)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 60.f, FColor::Red, Message);
	}
}

bool UNetworkGameInstance::HostGame(ULocalPlayer* LocalPlayer, const FString& GameType, const FString& InTravelURL)
{
	TravelURL = InTravelURL;
	ANetworkGameSession* GameSession = GetGameSession();
	if (GameSession)
	{
		DebugMessage(FString("HostGame"));
		OnCreatePresenceSessionCompleteDelegateHandle = GameSession->OnCreatePresenceSessionComplete().AddUObject(this, &UNetworkGameInstance::OnCreatePresenceSessionComplete);
		const FString& MapNameSubStr = MapLeftPath;
		const FString& ChoppedMapName = TravelURL.RightChop(MapNameSubStr.Len());
		const FString& MapName = ChoppedMapName.LeftChop(ChoppedMapName.Len() - ChoppedMapName.Find("?listen"));
		GameSession->HostSession(LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(), NAME_GameSession, GameType, MapName, true, true, 4);
	}
	return false;
}

bool UNetworkGameInstance::JoinSession(ULocalPlayer* LocalPlayer, int32 SessionIndexInSearchResults)
{
	ANetworkGameSession* GameSession = GetGameSession();
	if (GameSession)
	{
		OnJoinSessionCompleteDelegateHandle = GameSession->OnJoinSessionComplete().AddUObject(this, &UNetworkGameInstance::OnJoinSessionComplete);
		GameSession->JoinSession(LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(), NAME_GameSession, SessionIndexInSearchResults);
	}
	return false;
}

bool UNetworkGameInstance::JoinSession(ULocalPlayer* LocalPlayer, const FOnlineSessionSearchResult& SearchResult)
{
	ANetworkGameSession* GameSession = GetGameSession();
	if (GameSession)
	{
		OnJoinSessionCompleteDelegateHandle = GameSession->OnJoinSessionComplete().AddUObject(this, &UNetworkGameInstance::OnJoinSessionComplete);
		GameSession->JoinSession(LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(), NAME_GameSession, SearchResult);
	}
	return false;
}

void UNetworkGameInstance::ParseVersion(TArray<FString> content, FString SavePath)
{
	if (GameVersionSubsystem)
	{
		// PS->MountPak(content);
		// PS->OnPakDownloadingProcess().AddLambda([this](const int32 BytesSent, const int32 BytesReceived, const int32 FullSize)
		// {
		// 	this->DebugMessage(FString::Printf(TEXT("%f.2%%"), (float)BytesReceived / (float)FullSize * 100.f));
		// });
		// PS->OnOnePakDownloadComplete().AddLambda([this](TEnumAsByte<DownloadResult> Result)
		// {
		//     this->DebugMessage("One");
		// });
		// PS->OnAllPakDownloadComplete().AddLambda([this](TEnumAsByte<DownloadResult> Result)
		// {
		// 	this->DebugMessage("All");
		// });
		// PS->DownloadPakFile(content);
	}
}

FString UNetworkGameInstance::ParseURL(FString content)
{
	if (GameVersionSubsystem)
	{
		// return PS->ParseUrl(content);
	}
	return "";
}

TArray<FString> UNetworkGameInstance::ParsePak(FString content)
{
	if (GameVersionSubsystem)
	{
		GameVersionSubsystem->OnAllPakDownloadComplete().AddUObject(this, &UNetworkGameInstance::MountedAllPaks);
		GameVersionSubsystem->UpdateVersion(FPaths::ProjectSavedDir() + "test/ClientPak/");
		// PS->MountPak(content);
		// PS->OnPakDownloadingProcess().AddLambda([this](const int32 BytesSent, const int32 BytesReceived, const int32 FullSize)
		// {
		// 	this->DebugMessage(FString::Printf(TEXT("%f.2%%"), (float)BytesReceived / (float)FullSize * 100.f));
		// });
		// PS->OnOnePakDownloadComplete().AddLambda([this](TEnumAsByte<DownloadResult> Result)
		// {
		//     this->DebugMessage("One");
		// });
	} else
	{
		this->DebugMessage("GameVersionSubsystemNone");
	}
	return TArray<FString>();
}

void UNetworkGameInstance::HostGame()
{
	HostGame(GetFirstGamePlayer(), FString("FREE"), MapPath);
}

void UNetworkGameInstance::FindSessions()
{
	FindSessions(GetFirstGamePlayer(), false, false);
}

void UNetworkGameInstance::JoinSessions()
{
	JoinSession(GetFirstGamePlayer(), 0);
}

void UNetworkGameInstance::OnCreatePresenceSessionComplete(FName SessionName, bool bSuccess)
{
	ANetworkGameSession* const GameSession = GetGameSession();
	if (GameSession)
	{
		GameSession->OnCreatePresenceSessionComplete().Remove(OnCreatePresenceSessionCompleteDelegateHandle);
		FinishSessionCreation(bSuccess ? EOnJoinSessionCompleteResult::Success : EOnJoinSessionCompleteResult::UnknownError);
	}
}
